﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Windows;
using Xceed.Silverlight.Data;
using System.ComponentModel;

namespace Xceed.Silverlight.ListBox
{
  public abstract class ListBoxContainerConfigurationBase : DependencyObject , ISupportInitialize
  {
    #region Static Members

    private static readonly Size EstimatedSize = new Size( 20, 20 );

    #endregion Static Members

    #region Constructors

    internal ListBoxContainerConfigurationBase()
    {
    }

    internal ListBoxContainerConfigurationBase( ListBoxContainerConfigurationBase template )
    {
      this.IsSticky = template.IsSticky;
      m_cachedSize = template.CachedSize;

      this.ContainerStyle = template.ContainerStyle;
      this.ContentTemplate = template.ContentTemplate;

      this.LayoutMode = template.LayoutMode;
    }

    #endregion Constructors

    #region ConfigurationType Property

    public ConfigurationType ConfigurationType
    {
      get
      {
        return this.GetConfigurationType();
      }
    }

    #endregion

    #region CanDrag Internal Property

    internal virtual bool CanDrag
    {
      get
      {
        return true;
      }
    }

    #endregion

    #region CanStick Property

    public virtual bool CanStick
    {
      get
      {
        return false;
      }
    }

    #endregion CanStick Property

    #region IsSticky Property

    public static readonly DependencyProperty IsStickyProperty = DependencyProperty.Register(
      "IsSticky",
      typeof( bool ),
      typeof( ListBoxContainerConfigurationBase ),
      new PropertyMetadata(
        true,
        new PropertyChangedCallback( ListBoxContainerConfigurationBase.OnIsStickyChanged ) ) );

    public bool IsSticky
    {
      get
      {
        return ( bool )this.GetValue( ListBoxContainerConfigurationBase.IsStickyProperty );
      }
      set
      {
        this.SetValue( ListBoxContainerConfigurationBase.IsStickyProperty, value );
      }
    }

    private static void OnIsStickyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      ListBoxContainerConfigurationBase containerConfiguration = ( ListBoxContainerConfigurationBase )sender;
      bool isSticky = ( bool )e.NewValue;

      if( isSticky && !containerConfiguration.CanStick )
      {
        containerConfiguration.IsSticky = false;
        throw new ArgumentException( "An attempt was made to set as sticky a ContainerConfiguration that does not support it." );
      }
    }

    #endregion IsSticky Property

    #region ContentTemplate Property

    public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.Register(
       "ContentTemplate",
       typeof( DataTemplate ),
       typeof( ListBoxContainerConfigurationBase ),
       new PropertyMetadata( null, new PropertyChangedCallback( ListBoxContainerConfigurationBase.OnContentTemplateChanged ) ) );

    public DataTemplate ContentTemplate
    {
      get
      {
        return ( DataTemplate )this.GetValue( ListBoxContainerConfigurationBase.ContentTemplateProperty );
      }
      set
      {
        this.SetValue( ListBoxContainerConfigurationBase.ContentTemplateProperty, value );
      }
    }

    private static void OnContentTemplateChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      ListBoxContainerConfigurationBase containerConfigurationBase = ( ListBoxContainerConfigurationBase )sender;

      if( containerConfigurationBase.ContentTemplateChanged != null )
        containerConfigurationBase.ContentTemplateChanged( containerConfigurationBase, EventArgs.Empty );
    }

    internal event EventHandler ContentTemplateChanged;

    #endregion ContentTemplate Property

    #region ContainerStyle Property

    public static readonly DependencyProperty ContainerStyleProperty = DependencyProperty.Register(
       "ContainerStyle",
       typeof( Style ),
       typeof( ListBoxContainerConfigurationBase ),
       new PropertyMetadata( null, new PropertyChangedCallback( ListBoxContainerConfigurationBase.OnContainerStyleChanged ) ) );

    public Style ContainerStyle
    {
      get
      {
        return ( Style )this.GetValue( ListBoxContainerConfigurationBase.ContainerStyleProperty );
      }
      set
      {
        this.SetValue( ListBoxContainerConfigurationBase.ContainerStyleProperty, value );
      }
    }

    private static void OnContainerStyleChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      Style newStyle = e.NewValue as Style;
      ListBoxContainerConfigurationBase containerConfigurationBase = ( ListBoxContainerConfigurationBase )sender;

      if( containerConfigurationBase.ContainerStyleChanged != null )
        containerConfigurationBase.ContainerStyleChanged( containerConfigurationBase, EventArgs.Empty );
    }

    internal event EventHandler ContainerStyleChanged;

    #endregion ItemContainerStyle Property

    #region LayoutMode Property

    public static readonly DependencyProperty LayoutModeProperty = DependencyProperty.Register( 
      "LayoutMode", 
      typeof( ContainerLayoutMode ), 
      typeof( ListBoxContainerConfigurationBase ), 
      new PropertyMetadata( ContainerLayoutMode.Default ) );

    public ContainerLayoutMode LayoutMode
    {
      get 
      { 
        return ( ContainerLayoutMode )this.GetValue( ListBoxContainerConfigurationBase.LayoutModeProperty ); 
      }
      set 
      { 
        this.SetValue( ListBoxContainerConfigurationBase.LayoutModeProperty, value ); 
      }
    }

    #endregion


    #region Size Caching

    internal Size PrepareSize
    {
      get
      {
        if( Size.Equals( Size.Empty, m_cachedSize ) )
        {
          // Cache not initialized.
          // Use a estimated size instead.
          return ListBoxContainerConfigurationBase.EstimatedSize;
        }

        return m_cachedSize;
      }
    }

    internal Size CachedSize
    {
      get
      {
        return m_cachedSize;
      }
    }

    internal bool UpdateCachedSize( ListBoxContainer container )
    {
      if( container == null )
        throw new ArgumentNullException( "container" );

      DataPath dataPath = container.DataPath;
      Size oldCachedSize = this.CachedSize;
      Size updatedCachedSize;

      Size desiredSize;

      if( ( dataPath != null ) && ( !dataPath.LastChild.IsLoaded ) )
      {
        // The ListBoxGroupHeader should never have a desired Height/Width of 0.
        if( container.GetType() == typeof( ListBoxGroupHeader ) )
        {
          desiredSize = container.DesiredSize;
        }
        else
        {
          // Ensure to at least set m_cachedSize to the EstimatedSize
          desiredSize = ListBoxContainerConfigurationBase.EstimatedSize;
        }
      }
      else
      {
        desiredSize = container.DesiredSize;
      }

      updatedCachedSize = new Size(
        Math.Max( oldCachedSize.Width, desiredSize.Width ),
        Math.Max( oldCachedSize.Height, desiredSize.Height ) );

      if( Size.Equals( oldCachedSize, updatedCachedSize ) )
        return false;

      m_cachedSize = updatedCachedSize;

      this.OnCachedSizeChanged( new CachedSizeChangedEventArgs( oldCachedSize, updatedCachedSize ) );

      return true;
    }

    internal void OnCachedSizeChanged( CachedSizeChangedEventArgs e )
    {
      if( this.CachedSizeChanged != null )
        this.CachedSizeChanged( this, e );
    }

    internal event EventHandler<CachedSizeChangedEventArgs> CachedSizeChanged;

    #endregion Size Caching

    #region Internal Methods

    internal abstract ListBoxContainer CreateContainer();

    internal abstract ConfigurationType GetConfigurationType();

    protected internal abstract ListBoxContainerConfigurationBase CreateInstance();

    internal abstract void PrepareContainerForItem( ListBoxContainer container, object item );

    #endregion Internal Methods

    #region PRIVATE FIELDS

    private Size m_cachedSize = Size.Empty;

    #endregion PRIVATE FIELDS

    #region ISupportInitialize Members

    protected virtual void BeginInitCore()
    {
    }

    protected virtual void EndInitCore()
    {

    }

    void ISupportInitialize.BeginInit()
    {
      this.BeginInitCore();
    }

    void ISupportInitialize.EndInit()
    {
      this.EndInitCore();
    }

    #endregion
  }
}
